/*
    Authour: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

#ifndef CVML_SERIALIZATION_HPP
#define CVML_SERIALIZATION_HPP

typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned int u4; 

struct Stream
{
	virtual bool IsReading() = 0;
	virtual bool IsWriting() = 0;
	virtual void Read(u1& x) = 0;
	virtual void Write(u1 x) = 0;

	template<typename T>
	void Serialize(T& x) {
		if (IsReading())
			Read(x);
		else 
			Write(x);
	}

	void Serialize(u1& x) {
		if (IsReading()) 
			Read(x);
		else
			Write(x);
	}

	template<typename T>
	void Read(T& x)
	{
		u1* p = reinterpret_cast<u1*>(&x);
		for (size_t i = 0; i < sizeof(T); ++i) {
			Read(p[i]);
		}			
	}

	template<typename T>
	void Write(const T& x)
	{
		const u1* p = reinterpret_cast<const u1*>(&x);
		for (size_t i = 0; i < sizeof(T); ++i) {
			Write(p[i]);
		}			
	}
};

struct FileReadingStream : Stream
{
	FILE* f;

	FileReadingStream(const char* filename)
	{
		f = fopen(filename, "r");
	}

	~FileReadingStream()
	{
		fclose(f);
	}

	bool IsOpen()
	{
		return f != NULL;
	}

	bool IsReading() 
	{
		return true;
	}

	bool IsWriting()
	{
		return false;
	}
	
	void Read(u1& x) 
	{
		x = fgetc(f);
	}

	void Write() 
	{
		throw 1;
	}
};

struct FileWritingStream : Stream
{
	FILE* f;

	FileWritingStream(ConstString s)
	{
		f = fopen(s.c_str(), "w");
	}

	~FileWritingStream()
	{
		fclose(f);
	}

	bool IsOpen()
	{
		return f != NULL;
	}

	bool IsReading() 
	{
		return false;
	}

	bool IsWriting() 
	{
		return true;
	}
	
	void Write(u1 x) 
	{
		fputc(x, f);
	}

	void Read(u1& x) 
	{
		throw 1;
	}
};

struct Serializable 
{
	virtual void Serialize(Stream& stream) = 0;
};

#endif
